/*
 * Created by SharpDevelop.
 * User: David
 * Date: 2006-12-09
 * Time: 04:11
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;

namespace Labb4.Entity
{
	/// <summary>
	/// A control class that uses input in the form of key presses to determine the
	/// movement of an entity.
	/// </summary>
	public class ControlPad : Control
	{
		#region members
		
		/// <summary>
		/// The state of the "Up"-button (moves the entity forward in the current direction)
		/// </summary>
		protected bool		m_Up;
		/// <summary>
		/// The state of the "Down"-button (moves the entity backwards in the current direction, or breakes)
		/// </summary>
		protected bool		m_Down;
		
		/// <summary>
		/// The state of the "SoftLeft"-button (turns the direction softly to the left)
		/// </summary>
		protected bool		m_SoftLeft;
		/// <summary>
		/// The state of the "MediumLeft"-button (turns the direction to the left)
		/// </summary>
		protected bool		m_MediumLeft;
		/// <summary>
		/// The state of the "HardLeft"-button (turns the direction hard to the left)
		/// </summary>
		protected bool		m_HardLeft;
		
		/// <summary>
		/// The state of the "SoftRight"-button (turns the direction softly to the right)
		/// </summary>
		protected bool		m_SoftRight;
		/// <summary>
		/// The state of the "MediumRight"-button (turns the direction hard to the right)
		/// </summary>
		protected bool		m_MediumRight;
		/// <summary>
		/// The state of the "HardRight"-button (turns the direction hard to the right)
		/// </summary>
		protected bool		m_HardRight;
		
		/// <summary>
		/// The state of the "Ctrl"-button (adds more throttle)
		/// </summary>
		protected bool		m_Ctrl;
		/// <summary>
		/// The state of the "Shift"-button (adds even more throttle)
		/// </summary>
		protected bool		m_Shift;
		
		/// <summary>
		/// The state of the "Num0"-button (switches the animation)
		/// </summary>
		protected bool		m_Num0;
		/// <summary>
		/// The state of the "Num1"-button (switches the animation)
		/// </summary>
		protected bool		m_Num1;
		/// <summary>
		/// The state of the "Num2"-button (switches the animation)
		/// </summary>
		protected bool		m_Num2;
		/// <summary>
		/// The state of the "Num3"-button (switches the animation)
		/// </summary>
		protected bool		m_Num3;
		/// <summary>
		/// The state of the "Num4"-button (switches the animation)
		/// </summary>
		protected bool		m_Num4;
		/// <summary>
		/// The state of the "Num5"-button (switches the animation)
		/// </summary>
		protected bool		m_Num5;
		/// <summary>
		/// The state of the "Num6"-button (switches the animation)
		/// </summary>
		protected bool		m_Num6;
		/// <summary>
		/// The state of the "Num7"-button (switches the animation)
		/// </summary>
		protected bool		m_Num7;
		/// <summary>
		/// The state of the "Num8"-button (switches the animation)
		/// </summary>
		protected bool		m_Num8;
		/// <summary>
		/// The state of the "Num9"-button (switches the animation)
		/// </summary>
		protected bool		m_Num9;
		
		/// <summary>
		/// The amount of change applied to the direction when turning softly
		/// </summary>
		private float		m_SoftTurn;
		/// <summary>
		/// The amount of change applied to the direction when turning
		/// </summary>
		private float		m_MediumTurn;
		/// <summary>
		/// The amount of change applied to the direction when turning hard
		/// </summary>
		private float		m_HardTurn;
		
		/// <summary>
		/// The standard speed of the entity
		/// </summary>
		private float		m_StandardSpeed;
		/// <summary>
		/// The standard speed increase of the entity when extra throttle is applied
		/// </summary>
		private float		m_SpeedIncrease;
		/// <summary>
		/// How fast the entity changes from one speed to another
		/// </summary>
		private float		m_Acceleration;
		
		#endregion
		
		#region constructors
		
		/// <summary>
		/// Constructor, initializes members
		/// </summary>
		public ControlPad() :
			base()
		{
			m_Up = false;
			m_Down = false;
			
			m_SoftLeft = false;
			m_MediumLeft = false;
			m_HardLeft = false;
			
			m_SoftRight = false;
			m_MediumRight = false;
			m_HardRight = false;
			
			m_Ctrl = false;
			m_Shift = false;
			
			m_Num0 = false;
			m_Num1 = false;
			m_Num2 = false;
			m_Num3 = false;
			m_Num4 = false;
			m_Num5 = false;
			m_Num6 = false;
			m_Num7 = false;
			m_Num8 = false;
			m_Num9 = false;
			
			m_SoftTurn = 0.005f; //this was fine at 60 fps...
			m_MediumTurn = 0.01f;
			m_HardTurn = 0.02f;
			
			m_StandardSpeed = 75.0f;
			m_SpeedIncrease = 30.0f;
			m_Acceleration = 1.5f;
		}
		
		#endregion
		
		#region methods
		
		/// <summary>
		/// Registers a key press on the controler's pad.
		/// </summary>
		/// <param name="key">The key that's registered</param>
		/// <param name="pressed">The state of the key, true if pressed, false if released</param>
		public void Pad(PadKey key, bool pressed)
		{
			if(key == PadKey.UP)
			{
				m_Up = pressed;
			}
			
			if(key == PadKey.DOWN)
			{
				m_Down = pressed;
			}
			
			if(key == PadKey.SOFT_LEFT)
			{
				m_SoftLeft = pressed;
			}
			
			if(key == PadKey.MEDIUM_LEFT)
			{
				m_MediumLeft = pressed;
			}
			
			if(key == PadKey.HARD_LEFT)
			{
				m_HardLeft = pressed;
			}
			
			if(key == PadKey.SOFT_RIGHT)
			{
				m_SoftRight = pressed;
			}
			
			if(key == PadKey.MEDIUM_RIGHT)
			{
				m_MediumRight = pressed;
			}
			
			if(key == PadKey.HARD_RIGHT)
			{
				m_HardRight = pressed;
			}
			
			if(key == PadKey.MEDIUM_SPEED)
			{
				m_Ctrl = pressed;
			}
			
			if(key == PadKey.HIGH_SPEED)
			{
				m_Shift = pressed;
			}
			
			if(key == PadKey.ANIM_0)
			{
				m_Num0 = pressed;
			}
			
			if(key == PadKey.ANIM_1)
			{
				m_Num1 = pressed;
			}
			
			if(key == PadKey.ANIM_2)
			{
				m_Num2 = pressed;
			}
			
			if(key == PadKey.ANIM_3)
			{
				m_Num3 = pressed;
			}
			
			if(key == PadKey.ANIM_4)
			{
				m_Num4 = pressed;
			}
			
			if(key == PadKey.ANIM_5)
			{
				m_Num5 = pressed;
			}
			
			if(key == PadKey.ANIM_6)
			{
				m_Num6 = pressed;
			}
			
			if(key == PadKey.ANIM_7)
			{
				m_Num7 = pressed;
			}
			
			if(key == PadKey.ANIM_8)
			{
				m_Num8 = pressed;
			}
			
			if(key == PadKey.ANIM_9)
			{
				m_Num9 = pressed;
			}
		}
		
		/// <summary>
		/// Checks to see if a certain key is pressed or not
		/// </summary>
		/// <param name="key">The key to check</param>
		/// <returns></returns>
		public bool GetStateOf(PadKey key)
		{
			bool state = false;
			
			if(key == PadKey.UP)
			{
				state = m_Up;
			}
			
			if(key == PadKey.DOWN)
			{
				state = m_Down;
			}
			
			if(key == PadKey.SOFT_LEFT)
			{
				state = m_SoftLeft;
			}
			
			if(key == PadKey.MEDIUM_LEFT)
			{
				state = m_MediumLeft;
			}
			
			if(key == PadKey.HARD_LEFT)
			{
				state = m_HardLeft;
			}
			
			if(key == PadKey.SOFT_RIGHT)
			{
				state = m_SoftRight;
			}
			
			if(key == PadKey.MEDIUM_RIGHT)
			{
				state = m_MediumRight;
			}
			
			if(key == PadKey.HARD_RIGHT)
			{
				state = m_HardRight;
			}
			
			if(key == PadKey.MEDIUM_SPEED)
			{
				state = m_Ctrl;
			}
			
			if(key == PadKey.HIGH_SPEED)
			{
				state = m_Shift;
			}
			
			if(key == PadKey.ANIM_0)
			{
				state = m_Num0;
			}
			
			if(key == PadKey.ANIM_1)
			{
				state = m_Num1;
			}
			
			if(key == PadKey.ANIM_2)
			{
				state = m_Num2;
			}
			
			if(key == PadKey.ANIM_3)
			{
				state = m_Num3;
			}
			
			if(key == PadKey.ANIM_4)
			{
				state = m_Num4;
			}
			
			if(key == PadKey.ANIM_5)
			{
				state = m_Num5;
			}
			
			if(key == PadKey.ANIM_6)
			{
				state = m_Num6;
			}
			
			if(key == PadKey.ANIM_7)
			{
				state = m_Num7;
			}
			
			if(key == PadKey.ANIM_8)
			{
				state = m_Num8;
			}
			
			if(key == PadKey.ANIM_9)
			{
				state = m_Num9;
			}
			
			return state;
		}
		/// <summary>
		/// Sets some or all of the 6 members controling the entity's behaviour.
		/// If only 3 parameters are sent, these will affect SoftTurn, MediumTurn and HardTurn (in that order)
		/// If 6 parameters are sent, params 4, 5, and 6 will affect StandardSpeed, SpeedIncrease, and Acceleration (in that order)
		/// </summary>
		/// <param name="specs">Should be 3 or 6 floats, affecting settings in the controller</param>
		public void SetSpecifics(params float[] specs)
		{
			if(specs.Length > 2)
			{
				m_SoftTurn = specs[0];
				m_MediumTurn = specs[1];
				m_HardTurn = specs[2];
			}
			
			if(specs.Length > 5)
			{
				m_StandardSpeed = specs[3];
				m_SpeedIncrease = specs[4];
				m_Acceleration = specs[5];
			}
		}
		
		#endregion
		
		#region overrides
		
		/// <summary>
		/// Sets the direction and velocity of this controler's entity based on the values of
		/// the different control pad's "buttons"
		/// </summary>
		/// <param name="deltaTime">Time passed since last update. Unit is (ms)</param>
		public override void UpdateEntity(ref int deltaTime)
		{
			float		accumulatedAngleChange = 0.0f;
			float		acceleration = (m_Acceleration * FrameRateReCalc(ref deltaTime));
			float		targetSpeed = 0.0f;
			float		speedIncrease = 0.0f;
			
			if(m_Up)
			{
				targetSpeed = m_StandardSpeed;
				speedIncrease = (m_SpeedIncrease * FrameRateReCalc(ref deltaTime));
			}
			else
			{
				if(m_Down)
				{
					targetSpeed = -m_StandardSpeed;
					speedIncrease = (-m_SpeedIncrease * FrameRateReCalc(ref deltaTime));
				}
			}
			
			if(m_Ctrl)
			{
				targetSpeed += speedIncrease;
				acceleration += (m_Acceleration * FrameRateReCalc(ref deltaTime));
			}
			
			if(m_Shift)
			{
				targetSpeed += (speedIncrease * 2);
				acceleration += (m_Acceleration * FrameRateReCalc(ref deltaTime));
			}
			
			if(m_Entity.Velocity < targetSpeed)
			{
				m_Entity.Velocity += acceleration;
				
				if(targetSpeed < 0.0f)
				{
					m_Entity.Velocity = targetSpeed;
				}
			}
			
			if(m_Entity.Velocity > targetSpeed)
			{
				m_Entity.Velocity -= acceleration;
				
				if(m_Entity.Velocity < targetSpeed)
				{
					m_Entity.Velocity = targetSpeed;
				}
			}
			
			if(m_Entity.Velocity != 0.0f)
			{
				if(m_SoftLeft)
				{
					accumulatedAngleChange -= (m_SoftTurn * FrameRateReCalc(ref deltaTime));
				}
				
				if(m_MediumLeft)
				{
					accumulatedAngleChange -= (m_MediumTurn * FrameRateReCalc(ref deltaTime));
				}
				
				if(m_HardLeft)
				{
					accumulatedAngleChange -= (m_HardTurn * FrameRateReCalc(ref deltaTime));
				}
				
				if(m_SoftRight)
				{
					accumulatedAngleChange += (m_SoftTurn * FrameRateReCalc(ref deltaTime));
				}
				
				if(m_MediumRight)
				{
					accumulatedAngleChange += (m_MediumTurn * FrameRateReCalc(ref deltaTime));
				}
				
				if(m_HardRight)
				{
					accumulatedAngleChange += (m_HardTurn * FrameRateReCalc(ref deltaTime));
				}
				
				m_Entity.Direction += (accumulatedAngleChange * FrameRateReCalc(ref deltaTime));
			}
			
			if(m_Num0)
			{
				m_Entity.SelectAnimation(0);
				m_Num0 = false;
			}
			
			if(m_Num1)
			{
				m_Entity.SelectAnimation(1);
				m_Num1 = false;
			}
			
			if(m_Num2)
			{
				m_Entity.SelectAnimation(2);
				m_Num2 = false;
			}
			
			if(m_Num3)
			{
				m_Entity.SelectAnimation(3);
				m_Num3 = false;
			}
			
			if(m_Num4)
			{
				m_Entity.SelectAnimation(4);
				m_Num4 = false;
			}
			
			if(m_Num5)
			{
				m_Entity.SelectAnimation(5);
				m_Num5 = false;
			}
			
			if(m_Num6)
			{
				m_Entity.SelectAnimation(6);
				m_Num6 = false;
			}
			
			if(m_Num7)
			{
				m_Entity.SelectAnimation(7);
				m_Num7 = false;
			}
			
			if(m_Num8)
			{
				m_Entity.SelectAnimation(8);
				m_Num8 = false;
			}
			
			if(m_Num9)
			{
				m_Entity.SelectAnimation(9);
				m_Num9 = false;
			}
		}
		
		#endregion
		
		#region properties
		
		/// <summary>
		/// The size of the SoftTurn (set/get)
		/// </summary>
		public float SoftTurn
		{
			get
			{
				return m_SoftTurn;
			}
			
			set
			{
				m_SoftTurn = value;
			}
		}
		
		/// <summary>
		/// The size of the MediumTurn (set/get)
		/// </summary>
		public float MediumTurn
		{
			get
			{
				return m_MediumTurn;
			}
			
			set
			{
				m_MediumTurn = value;
			}
		}
		
		/// <summary>
		/// The size of the HardTurn (set/get)
		/// </summary>
		public float HardTurn
		{
			get
			{
				return m_HardTurn;
			}
			
			set
			{
				m_HardTurn = value;
			}
		}
		
		/// <summary>
		/// The size of the StandardSpeed (set/get)
		/// </summary>
		public float StandardSpeed
		{
			get
			{
				return m_StandardSpeed;
			}
			
			set
			{
				m_StandardSpeed = value;
			}
		}
		
		/// <summary>
		/// The size of the SpeedIncrease (set/get)
		/// </summary>
		public float SpeedIncrease
		{
			get
			{
				return m_SpeedIncrease;
			}
			
			set
			{
				m_SpeedIncrease = value;
			}
		}
		
		/// <summary>
		/// The size of the Acceleration (set/get)
		/// </summary>
		public float Acceleration
		{
			get
			{
				return m_Acceleration;
			}
			
			set
			{
				m_Acceleration = value;
			}
		}
		
		#endregion
		
		#region private methods
		
		/// <summary>
		/// Calculates the amount of change based upon the time passed since last update
		/// </summary>
		/// <param name="deltaTime"></param>
		/// <returns></returns>
		private float FrameRateReCalc(ref int deltaTime)
		{
			return (60.0f * ((float)deltaTime / 1000.0f));
		}
		
		#endregion
	}
}
